import crypto from 'crypto'
import fs from 'fs/promises'
import { prisma } from '@/lib/database'
import { ValidationError, NotFoundError } from '@/middleware/errorHandler'

export interface SignatureKeyPair {
  publicKey: string
  privateKey: string
  keyId: string
}

export interface SignatureResult {
  signature: string
  keyId: string
  algorithm: string
  timestamp: number
}

export interface VerificationResult {
  isValid: boolean
  keyId: string
  algorithm: string
  timestamp: number
  issuer?: string
  error?: string
}

export interface CertificateInfo {
  id: string
  keyId: string
  issuer: string
  subject: string
  validFrom: Date
  validTo: Date
  fingerprint: string
  status: 'active' | 'revoked' | 'expired'
}

export class SignatureService {
  private readonly algorithm = 'RSA-SHA256'
  private readonly keySize = 2048
  private readonly signatureVersion = '1.0'

  // 生成新的密钥对
  async generateKeyPair(issuer: string): Promise<SignatureKeyPair> {
    const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
      modulusLength: this.keySize,
      publicKeyEncoding: {
        type: 'spki',
        format: 'pem'
      },
      privateKeyEncoding: {
        type: 'pkcs8',
        format: 'pem'
      }
    })

    // 生成密钥ID
    const keyId = this.generateKeyId(publicKey)

    // 保存到数据库
    await prisma.signingCertificate.create({
      data: {
        keyId,
        issuer,
        subject: issuer,
        publicKey,
        privateKey,
        algorithm: this.algorithm,
        keySize: this.keySize,
        validFrom: new Date(),
        validTo: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000), // 1年有效期
        fingerprint: this.generateFingerprint(publicKey),
        status: 'active'
      }
    })

    return { publicKey, privateKey, keyId }
  }

  // 为插件版本生成数字签名
  async signPluginVersion(versionId: string, signerKeyId?: string): Promise<SignatureResult> {
    // 获取插件版本信息
    const version = await prisma.pluginVersion.findUnique({
      where: { id: versionId },
      include: {
        plugin: {
          include: {
            developer: true
          }
        }
      }
    })

    if (!version) {
      throw new NotFoundError('Plugin version not found')
    }

    // 获取签名密钥
    const signingKey = await this.getSigningKey(signerKeyId)
    
    // 读取插件文件
    await fs.readFile(version.filePath)
    
    // 创建签名数据
    const signatureData = {
      signatureVersion: this.signatureVersion,
      pluginId: version.pluginId,
      pluginName: version.plugin.name,
      pluginVersion: version.version,
      fileHash: version.fileHash,
      fileSize: version.fileSize.toString(),
      developer: version.plugin.developer.username,
      timestamp: Date.now(),
      manifest: version.manifest
    }

    // 生成签名
    const dataToSign = JSON.stringify(signatureData, null, 0)
    const signature = crypto.sign(this.algorithm, Buffer.from(dataToSign), signingKey.privateKey)
    const signatureBase64 = signature.toString('base64')

    const result: SignatureResult = {
      signature: signatureBase64,
      keyId: signingKey.keyId,
      algorithm: this.algorithm,
      timestamp: signatureData.timestamp
    }

    // 更新数据库中的签名信息
    await prisma.pluginVersion.update({
      where: { id: versionId },
      data: {
        signature: JSON.stringify({
          ...result,
          signatureData
        })
      }
    })

    return result
  }

  // 验证插件签名
  async verifyPluginSignature(versionId: string): Promise<VerificationResult> {
    const version = await prisma.pluginVersion.findUnique({
      where: { id: versionId },
      include: {
        plugin: {
          include: {
            developer: true
          }
        }
      }
    })

    if (!version || !version.signature) {
      return {
        isValid: false,
        keyId: '',
        algorithm: '',
        timestamp: 0,
        error: 'No signature found'
      }
    }

    try {
      const signatureInfo = JSON.parse(version.signature as string)
      const { signature, keyId, algorithm, timestamp, signatureData } = signatureInfo

      // 获取公钥
      const certificate = await prisma.signingCertificate.findUnique({
        where: { keyId }
      })

      if (!certificate) {
        return {
          isValid: false,
          keyId,
          algorithm,
          timestamp,
          error: 'Certificate not found'
        }
      }

      if (certificate.status !== 'active') {
        return {
          isValid: false,
          keyId,
          algorithm,
          timestamp,
          error: `Certificate is ${certificate.status}`
        }
      }

      // 验证证书是否过期
      if (new Date() > certificate.validTo) {
        return {
          isValid: false,
          keyId,
          algorithm,
          timestamp,
          error: 'Certificate expired'
        }
      }

      // 重新构建签名数据并验证
      const dataToVerify = JSON.stringify(signatureData, null, 0)
      const signatureBuffer = Buffer.from(signature, 'base64')
      
      const isValid = crypto.verify(
        algorithm,
        Buffer.from(dataToVerify),
        certificate.publicKey,
        signatureBuffer
      )

      return {
        isValid,
        keyId,
        algorithm,
        timestamp,
        issuer: certificate.issuer,
        error: isValid ? undefined : 'Signature verification failed'
      }

    } catch (error) {
      return {
        isValid: false,
        keyId: '',
        algorithm: '',
        timestamp: 0,
        error: `Signature parsing error: ${error instanceof Error ? error.message : 'Unknown error'}`
      }
    }
  }

  // 获取证书信息
  async getCertificateInfo(keyId: string): Promise<CertificateInfo | null> {
    const certificate = await prisma.signingCertificate.findUnique({
      where: { keyId }
    })

    if (!certificate) {
      return null
    }

    return {
      id: certificate.id,
      keyId: certificate.keyId,
      issuer: certificate.issuer,
      subject: certificate.subject,
      validFrom: certificate.validFrom,
      validTo: certificate.validTo,
      fingerprint: certificate.fingerprint,
      status: certificate.status as 'active' | 'revoked' | 'expired'
    }
  }

  // 撤销证书
  async revokeCertificate(keyId: string, reason: string): Promise<void> {
    await prisma.signingCertificate.update({
      where: { keyId },
      data: {
        status: 'revoked',
        revokedAt: new Date(),
        revocationReason: reason
      }
    })
  }

  // 获取所有活跃证书
  async getActiveCertificates(): Promise<CertificateInfo[]> {
    const certificates = await prisma.signingCertificate.findMany({
      where: {
        status: 'active',
        validTo: {
          gt: new Date()
        }
      },
      orderBy: { createdAt: 'desc' }
    })

    return certificates.map(cert => ({
      id: cert.id,
      keyId: cert.keyId,
      issuer: cert.issuer,
      subject: cert.subject,
      validFrom: cert.validFrom,
      validTo: cert.validTo,
      fingerprint: cert.fingerprint,
      status: cert.status as 'active' | 'revoked' | 'expired'
    }))
  }

  // 私有方法：生成密钥ID
  private generateKeyId(publicKey: string): string {
    const hash = crypto.createHash('sha256').update(publicKey).digest('hex')
    return hash.substring(0, 16).toUpperCase()
  }

  // 私有方法：生成指纹
  private generateFingerprint(publicKey: string): string {
    return crypto.createHash('sha256').update(publicKey).digest('hex').toUpperCase()
  }

  // 私有方法：获取签名密钥
  private async getSigningKey(keyId?: string) {
    let certificate

    if (keyId) {
      certificate = await prisma.signingCertificate.findUnique({
        where: { keyId }
      })
    } else {
      // 使用默认的活跃证书
      certificate = await prisma.signingCertificate.findFirst({
        where: {
          status: 'active',
          validTo: {
            gt: new Date()
          }
        },
        orderBy: { createdAt: 'desc' }
      })
    }

    if (!certificate) {
      throw new NotFoundError('No valid signing certificate found')
    }

    if (certificate.status !== 'active') {
      throw new ValidationError(`Certificate is ${certificate.status}`)
    }

    if (new Date() > certificate.validTo) {
      throw new ValidationError('Certificate expired')
    }

    return certificate
  }
}
